home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1991 / 02 / nelson / model-2.c < prev    next >
C/C++ Source or Header  |  1990-05-25  |  28KB  |  703 lines

  1. /*
  2.  * Listing 12 -- model-2.c
  3.  *
  4.  * This module contains all of the modeling functions used with
  5.  * comp-2.c and expand-2.c.  This modeling unit keeps track of
  6.  * all contexts from 0 up to max_order, which defaults to 3.
  7.  * In addition, there is a special context -1 which is a fixed model
  8.  * used to encode previously unseen characters, and a context -2
  9.  * which is used to encode EOF and FLUSH messages.
  10.  *
  11.  * Each context is stored in a special CONTEXT structure, which is
  12.  * documented below.  Context tables are not created until the
  13.  * context is seen, and they are never destroyed.
  14.  *
  15.  */
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include "coder.h"
  20. #include "model.h"
  21.  
  22. /*
  23.  * This program consumes massive amounts of memory.  One way to
  24.  * handle large amounts of memory is to use Zortech's __handle
  25.  * pointer type.  So that my code will run with other compilers
  26.  * as well, the handle stuff gets redefined when using other
  27.  * compilers.
  28.  */
  29. #ifdef __ZTC__
  30. #include <handle.h>
  31. #else
  32. #define __handle
  33. #define handle_calloc( a )        calloc( (a), 1 )
  34. #define handle_realloc( a, b )    realloc( (a), (b) )
  35. #define handle_free( a )          free( (a) )
  36. #endif
  37.  
  38. /* A context table contains a list of the counts for all symbols
  39.  * that have been seen in the defined context.  For example, a
  40.  * context of "Zor" might have only had 2 different characters
  41.  * appear.  't' might have appeared 10 times, and 'l' might have
  42.  * appeared once.  These two counts are stored in the context
  43.  * table.  The counts are stored in the STATS structure.  All of
  44.  * the counts for a given context are stored in and array of STATS.
  45.  * As new characters are added to a particular contexts, the STATS
  46.  * array will grow.  Sometimes, the STATS array will shrink
  47.  * after flushing the model.
  48.  */
  49. typedef struct {
  50.                 unsigned char symbol;
  51.                 unsigned char counts;
  52.                } STATS;
  53.  
  54. /*
  55.  * Each context has to have links to higher order contexts.  These
  56.  * links are used to navigate through the context tables.  For example,
  57.  * to find the context table for "ABC", I start at the order 0 table,
  58.  * then find the pointer to the "A" context table by looking through
  59.  * then LINKS array.  At that table, we find the "B" link and go to
  60.  * that table.  The process continues until the destination table is
  61.  * found.  The table pointed to by the LINKS array corresponds to the
  62.  * symbol found at the same offset in the STATS table.  The reason that
  63.  * LINKS is in a separate structure instead of being combined with
  64.  * STATS is to save space.  All of the leaf context nodes don't need
  65.  * next pointers, since they are in the highest order context.  In the
  66.  * leaf nodes, the LINKS array is a NULL pointers.
  67.  */
  68. typedef struct {
  69.                  struct context *next;
  70.                } LINKS;
  71.  
  72. /*
  73.  * The CONTEXT structure holds all of the know information about
  74.  * a particular context.  The links and stats pointers are discussed
  75.  * immediately above here.  The max_index element gives the maximum
  76.  * index that can be applied to the stats or link array.  When the
  77.  * table is first created, and stats is set to NULL, max_index is set
  78.  * to -1.  As soon as single element is added to stats, max_index is
  79.  * incremented to 0.
  80.  *
  81.  * The lesser context pointer is a navigational aid.  It points to
  82.  * the context that is one less than the current order.  For example,
  83.  * if the current context is "ABC", the lesser_context pointer will
  84.  * point to "BC".  The reason for maintaining this pointer is that
  85.  * this particular bit of table searching is done frequently, but
  86.  * the pointer only needs to be built once, when the context is
  87.  * created.
  88.  */
  89. typedef struct context {
  90.                          int max_index;
  91.                          LINKS __handle *links;
  92.                          STATS __handle *stats;
  93.                          struct context *lesser_context;
  94.                        } CONTEXT;
  95. /*
  96.  * max_order is the maximum order that will be maintained by this
  97.  * program.  EXPAND-2 and COMP-2 both will modify this int based
  98.  * on command line parameters.
  99.  */
  100. int max_order=3;
  101. /*
  102.  * *contexts[] is an array of current contexts.  If I want to find
  103.  * the order 0 context for the current state of the model, I just
  104.  * look at contexts[0].  This array of context pointers is set up
  105.  * every time the model is updated.
  106.  */
  107. CONTEXT **contexts;
  108. /*
  109.  * current_order contains the current order of the model.  It starts
  110.  * at max_order, and is decremented every time an ESCAPE is sent.  It
  111.  * will only go down to -1 for normal symbols, but can go to -2 for
  112.  * EOF and FLUSH.
  113.  */
  114. int current_order;
  115. /*
  116.  * This variable tells COMP-2.C that the FLUSH symbol can be
  117.  * sent using this model.
  118.  */
  119. int flushing_enabled=1;
  120. /*
  121.  * This table contains the cumulative totals for the current context.
  122.  * Because this program is using exclusion, totals has to be calculated
  123.  * every time a context is used.  The scoreboard array keeps track of
  124.  * symbols that have appeared in higher order models, so that they
  125.  * can be excluded from lower order context total calculations.
  126.  */
  127. short int totals[ 258 ];
  128. char scoreboard[ 256 ];
  129.  
  130. /*
  131.  * Local procedure declarations.
  132.  */
  133. void error_exit( char *message );
  134. void update_table( CONTEXT *table, unsigned char symbol );
  135. void rescale_table( CONTEXT *table );
  136. void totalize_table( CONTEXT *table );
  137. CONTEXT *shift_to_next_context( CONTEXT *table, unsigned char c, int order);
  138. CONTEXT *allocate_next_order_table( CONTEXT *table,
  139.                                     unsigned char symbol,
  140.                                     CONTEXT *lesser_context );
  141.  
  142. /*
  143.  * This routine has to get everything set up properly so that
  144.  * the model can be maintained properly.  The first step is to create
  145.  * the *contexts[] array used later to find current context tables.
  146.  * The *contexts[] array indices go from -2 up to max_order, so
  147.  * the table needs to be fiddled with a little.  This routine then
  148.  * has to create the special order -2 and order -1 tables by hand,
  149.  * since they aren't quite like other tables.  Then the current
  150.  * context is set to \0, \0, \0, ... and the appropriate tables
  151.  * are built to support that context.  The current order is set
  152.  * to max_order, the scoreboard is cleared, and the system is
  153.  * ready to go.
  154.  */
  155.  
  156. void initialize_model()
  157. {
  158.     int i;
  159.     CONTEXT *null_table;
  160.     CONTEXT *control_table;
  161.  
  162.     current_order = max_order;
  163.     contexts = (CONTEXT **) calloc( sizeof( CONTEXT * ), 10 );
  164.     if ( contexts == NULL )
  165.         error_exit( "Failure #1: allocating context table!" );
  166.     contexts += 2;
  167.     null_table = (CONTEXT *) calloc( sizeof( CONTEXT ), 1 );
  168.     if ( null_table == NULL )
  169.         error_exit( "Failure #2: allocating null table!" );
  170.     null_table->max_index = -1;
  171.     contexts[ -1 ] = null_table;
  172.     for ( i = 0 ; i <= max_order ; i++ )
  173.         contexts[ i ] = allocate_next_order_table( contexts[ i-1 ],
  174.                                                0,
  175.                                                contexts[ i-1 ] );
  176.     handle_free( (char __handle *) null_table->stats );
  177.     null_table->stats =
  178.          (STATS __handle *) handle_calloc( sizeof( STATS ) * 256 );
  179.     if ( null_table->stats == NULL )
  180.         error_exit( "Failure #3: allocating null table!" );
  181.     null_table->max_index = 255;
  182.     for ( i=0 ; i < 256 ; i++ )
  183.     {
  184.         null_table->stats[ i ].symbol = (unsigned char) i;
  185.         null_table->stats[ i ].counts = 1;
  186.     }
  187.  
  188.     control_table = (CONTEXT *) calloc( sizeof(CONTEXT), 1 );
  189.     if ( control_table == NULL )
  190.         error_exit( "Failure #4: allocating null table!" );
  191.     control_table->stats =
  192.          (STATS __handle *) handle_calloc( sizeof( STATS ) * 2 );
  193.     if ( control_table->stats == NULL )
  194.         error_exit( "Failure #5: allocating null table!" );
  195.     contexts[ -2 ] = control_table;
  196.     control_table->max_index = 1;
  197.     control_table->stats[ 0 ].symbol = -FLUSH;
  198.     control_table->stats[ 0 ].counts = 1;
  199.     control_table->stats[ 1 ].symbol =- DONE;
  200.     control_table->stats[ 1 ].counts = 1;
  201.  
  202.     for ( i = 0 ; i < 256 ; i++ )
  203.         scoreboard[ i ] = 0;
  204. }
  205. /*
  206.  * This is a utility routine used to create new tables when a new
  207.  * context is created.  It gets a pointer to the current context,
  208.  * and gets the symbol that needs to be added to it.  It also needs
  209.  * a pointer to the lesser context for the table that is to be
  210.  * created.  For example, if the current context was "ABC", and the
  211.  * symbol 'D' was read in, add_character_to_model would need to
  212.  * create the new context "BCD".  This routine would get called
  213.  * with a pointer to "BC", the symbol 'D', and a pointer to context
  214.  * "CD".  This routine then creates a new table for "BCD", adds it
  215.  * to the link table for "BC", and gives "BCD" a back pointer to
  216.  * "CD".  Note that finding the lesser context is a difficult
  217.  * task, and isn't done here.  This routine mainly worries about
  218.  * modifying the stats and links fields in the current context.
  219.  */
  220.  
  221. CONTEXT *allocate_next_order_table( CONTEXT *table,
  222.                                     unsigned char symbol,
  223.                                     CONTEXT *lesser_context )
  224. {
  225.     CONTEXT *new_table;
  226.     int i;
  227.     unsigned int new_size;
  228.  
  229.     for ( i = 0 ; i <= table->max_index ; i++ )
  230.         if ( table->stats[ i ].symbol == symbol )
  231.             break;
  232.     if ( i > table->max_index )
  233.     {
  234.         table->max_index++;
  235.         new_size = sizeof( LINKS );
  236.         new_size *= table->max_index + 1;
  237.         if ( table->links == NULL )
  238.             table->links = (LINKS __handle *) handle_calloc( new_size );
  239.         else
  240.             table->links = (LINKS __handle *)
  241.                  handle_realloc( (char __handle *) table->links, new_size );
  242.         new_size = sizeof( STATS );
  243.         new_size *= table->max_index + 1;
  244.         if ( table->stats == NULL )
  245.             table->stats = (STATS __handle *) handle_calloc( new_size );
  246.         else
  247.             table->stats = (STATS __handle *)
  248.                 handle_realloc( (char __handle *) table->stats, new_size );
  249.         if ( table->links == NULL )
  250.             error_exit( "Failure #6: allocating new table" );
  251.         if ( table->stats == NULL )
  252.             error_exit( "Failure #7: allocating new table" );
  253.         table->stats[ i ].symbol = symbol;
  254.         table->stats[ i ].counts = 0;
  255.     }
  256.     new_table = (CONTEXT *) calloc( sizeof( CONTEXT ), 1 );
  257.     if ( new_table == NULL )
  258.         error_exit( "Failure #8: allocating new table" );
  259.     new_table->max_index = -1;
  260.     table->links[ i ].next = new_table;
  261.     new_table->lesser_context = lesser_context;
  262.     return( new_table );
  263. }
  264.  
  265. /*
  266.  * This routine is called to increment the counts for the current
  267.  * contexts.  It is called after a character has been encoded or
  268.  * decoded.  All it does is call update_table for each of the
  269.  * current contexts, which does the work of incrementing the count.
  270.  * This particular version of update_model() practices update exclusion,
  271.  * which means that if lower order models weren't used to encode
  272.  * or decode the character, they don't get their counts updated.
  273.  * This seems to improve compression performance quite a bit.
  274.  * To disable update exclusion, the loop would be changed to run
  275.  * from 0 to max_order, instead of current_order to max_order.
  276.  */
  277. void update_model( int symbol )
  278. {
  279.     int i;
  280.     int local_order;
  281.  
  282.     if ( current_order < 0 )
  283.         local_order = 0;
  284.     else
  285.         local_order = current_order;
  286.     if ( symbol >= 0 )
  287.     {
  288.         while ( local_order <= max_order )
  289.         {
  290.             if ( symbol >= 0 )
  291.                 update_table( contexts[ local_order ], (unsigned char) symbol );
  292.             local_order++;
  293.         }
  294.     }
  295.     current_order = max_order;
  296.     for ( i = 0 ; i < 256 ; i++ )
  297.         scoreboard[ i ] = 0;
  298. }
  299. /*
  300.  * This routine is called to update the count for a particular symbol
  301.  * in a particular table.  The table is one of the current contexts,
  302.  * and the symbol is the last symbol encoded or decoded.  In principle
  303.  * this is a fairly simple routine, but a couple of complications make
  304.  * things a little messier.  First of all, the given table may not
  305.  * already have the symbol defined in its statistics table.  If it
  306.  * doesn't, the stats table has to grow and have the new guy added
  307.  * to it.  Secondly, the symbols are kept in sorted order by count
  308.  * in the table so as that the table can be trimmed during the flush
  309.  * operation.  When this symbol is incremented, it might have to be moved
  310.  * up to reflect its new rank.  Finally, since the counters are only
  311.  * bytes, if the count reaches 255, the table absolutely must be rescaled
  312.  * to get the counts back down to a reasonable level.
  313.  */
  314. void update_table( CONTEXT *table, unsigned char symbol )
  315. {
  316.     int i;
  317.     int index;
  318.     unsigned char temp;
  319.     CONTEXT *temp_ptr;
  320.     unsigned int new_size;
  321. /*
  322.  * First, find the symbol in the appropriate context table.  The first
  323.  * symbol in the table is the most active, so start there.
  324.  */
  325.     index = 0;
  326.     while ( index <= table->max_index &&
  327.             table->stats[index].symbol != symbol )
  328.         index++;
  329.     if ( index > table->max_index )
  330.     {
  331.         table->max_index++;
  332.         new_size = sizeof( LINKS );
  333.         new_size *= table->max_index + 1;
  334.         if ( current_order < max_order )
  335.         {
  336.             if ( table->max_index == 0 )
  337.                 table->links = (LINKS __handle *) handle_calloc( new_size );
  338.             else
  339.                 table->links = (LINKS __handle *)
  340.                    handle_realloc( (char __handle *) table->links, new_size );
  341.             if ( table->links == NULL )
  342.                 error_exit( "Error #9: reallocating table space!" );
  343.             table->links[ index ].next = NULL;
  344.         }
  345.         new_size = sizeof( STATS );
  346.         new_size *= table->max_index + 1;
  347.         if (table->max_index==0)
  348.             table->stats = (STATS __handle *) handle_calloc( new_size );
  349.         else
  350.             table->stats = (STATS __handle *)
  351.                 handle_realloc( (char __handle *) table->stats, new_size );
  352.         if ( table->stats == NULL )
  353.             error_exit( "Error #10: reallocating table space!" );
  354.         table->stats[ index ].symbol = symbol;
  355.         table->stats[ index ].counts = 0;
  356.     }
  357. /*
  358.  * Now I move the symbol to the front of its list.
  359.  */
  360.     i = index;
  361.     while ( i > 0 &&
  362.             table->stats[ index ].counts == table->stats[ i-1 ].counts )
  363.         i--;
  364.     if ( i != index )
  365.     {
  366.         temp = table->stats[ index ].symbol;
  367.         table->stats[ index ].symbol = table->stats[ i ].symbol;
  368.         table->stats[ i ].symbol = temp;
  369.         if ( table->links != NULL )
  370.         {
  371.             temp_ptr = table->links[ index ].next;
  372.             table->links[ index ].next = table->links[ i ].next;
  373.             table->links[ i ].next = temp_ptr;
  374.         }
  375.         index = i;
  376.     }
  377. /*
  378.  * The switch has been performed, now I can update the counts
  379.  */
  380.     table->stats[ index ].counts++;
  381.     if ( table->stats[ index ].counts == 255 )
  382.         rescale_table( table );
  383. }
  384.  
  385. /*
  386.  * This routine is called when a given symbol needs to be encoded.
  387.  * It is the job of this routine to find the symbol in the context
  388.  * table associated with the current table, and return the low and
  389.  * high counts associated with that symbol, as well as the scale.
  390.  * Finding the table is simple.  Unfortunately, once I find the table,
  391.  * I have to build the table of cumulative counts, which is
  392.  * expensive, and is done elsewhere.  If the symbol is found in the
  393.  * table, the appropriate counts are returned.  If the symbols is
  394.  * not found, the ESCAPE symbol probabilities are returned, and
  395.  * the current order is reduced.  Note also the kludge to support
  396.  * the order -2 character set, which consists of negative numbers
  397.  * instead of unsigned chars.  This insures that no match will every
  398.  * be found for the EOF or FLUSH symbols in any "normal" table.
  399.  */
  400. int convert_int_to_symbol( int c, SYMBOL *s )
  401. {
  402.     int i;
  403.     CONTEXT *table;
  404.  
  405.     table = contexts[ current_order ];
  406.     totalize_table( table );
  407.     s->scale = totals[ 0 ];
  408.     if ( current_order == -2 )
  409.         c = -c;
  410.     for ( i = 0 ; i <= table->max_index ; i++ )
  411.     {
  412.         if ( c == (int) table->stats[ i ].symbol )
  413.         {
  414.             if ( table->stats[ i ].counts == 0 )
  415.                 break;
  416.             s->low_count = totals[ i+2 ];
  417.             s->high_count = totals[ i+1 ];
  418.             return( 0 );
  419.         }
  420.     }
  421.     s->low_count = totals[ 1 ];
  422.     s->high_count = totals[ 0 ];
  423.     current_order--;
  424.     return( 1 );
  425. }
  426. /*
  427.  * This routine is called when decoding an arithmetic number.  In
  428.  * order to decode the present symbol, the current scale in the
  429.  * model must be determined.  This requires looking up the current
  430.  * table, then building the totals table.  Once that is done, the
  431.  * cumulative total table has the symbol scale at element 0.
  432.  */
  433. void get_symbol_scale( SYMBOL *s )
  434. {
  435.     CONTEXT *table;
  436.  
  437.     table = contexts[ current_order ];
  438.     totalize_table( table );
  439.     s->scale = totals[ 0 ];
  440. }
  441.  
  442. /*
  443.  * This routine is called during decoding.  It is given a count that
  444.  * came out of the arithmetic decoder, and has to find the symbol that
  445.  * matches the count.  The cumulative totals are already stored in the
  446.  * totals[] table, form the call to get_symbol_scale, so this routine
  447.  * just has to look through that table.  Once the match is found,
  448.  * the appropriate character is returned to the caller.  Two possible
  449.  * complications.  First, the character might be the ESCAPE character,
  450.  * in which case the current_order has to be decremented.  The other
  451.  * complication is that the order might be -2, in which case we return
  452.  * the negative of the symbol so it isn't confused with a normal
  453.  * symbol.
  454.  */
  455. int convert_symbol_to_int( int count, SYMBOL *s)
  456. {
  457.     int c;
  458.     CONTEXT *table;
  459.  
  460.     table = contexts[ current_order ];
  461.     for ( c = 0; count < totals[ c ] ; c++ )
  462.         ;
  463.     s->high_count = totals[ c-1 ];
  464.     s->low_count = totals[ c ];
  465.     if ( c == 1 )
  466.     {
  467.         current_order--;
  468.         return( ESCAPE );
  469.     }
  470.     if ( current_order < -1 )
  471.         return( (int) -table->stats[ c-2 ].symbol );
  472.     else
  473.         return( table->stats[ c-2 ].symbol );
  474. }
  475.  
  476.  
  477. /*
  478.  * After the model has been updated for a new character, this routine
  479.  * is called to "shift" into the new context.  For example, if the
  480.  * last context was "ABC", and the symbol 'D' had just been processed,
  481.  * this routine would want to update the context pointers to that
  482.  * contexts[1]=="D", contexts[2]=="CD" and contexts[3]=="BCD".  The
  483.  * potential problem is that some of these tables may not exist.
  484.  * The way this is handled is by the shift_to_next_context routine.
  485.  * It is passed a pointer to the "ABC" context, along with the symbol
  486.  * 'D', and its job is to return a pointer to "BCD".  Once we have
  487.  * "BCD", we can follow the lesser context pointers in order to get
  488.  * the pointers to "CD" and "C".  The hard work was done in
  489.  * shift_to_context().
  490.  */
  491. void add_character_to_model( int c )
  492. {
  493.     int i;
  494.     if ( max_order < 0 || c < 0 )
  495.        return;
  496.     contexts[ max_order ] =
  497.        shift_to_next_context( contexts[ max_order ],
  498.                               (unsigned char) c, max_order );
  499.     for ( i = max_order-1 ; i > 0 ; i-- )
  500.         contexts[ i ] = contexts[ i+1 ]->lesser_context;
  501. }
  502.  
  503. /*
  504.  * This routine is called when adding a new character to the model. From
  505.  * the previous example, if the current context was "ABC", and the new
  506.  * symbol was 'D', this routine would get called with a pointer to
  507.  * context table "ABC", and symbol 'D', with order max_order.  What this
  508.  * routine needs to do then is to find the context table "BCD".  This
  509.  * should be an easy job, and it is if the table already exists.  All
  510.  * we have to in that case is follow the back pointer from "ABC" to "BC".
  511.  * We then search the link table of "BC" until we find the linke to "D".
  512.  * That link points to "BCD", and that value is then returned to the
  513.  * caller.  The problem crops up when "BC" doesn't have a pointer to
  514.  * "BCD".  This generally means that the "BCD" context has not appeared
  515.  * yet.  When this happens, it means a new table has to be created and
  516.  * added to the "BC" table.  That can be done with a single call to
  517.  * the allocate_new_table routine.  The only problem is that the
  518.  * allocate_new_table routine wants to know what the lesser context for
  519.  * the new table is going to be.  In other words, when I create "BCD",
  520.  * I need to know where "CD" is located.  In order to find "CD", I
  521.  * have to recursively call shift_to_next_context, passing it a pointer
  522.  * to context "C" and they symbol 'D'.  It then returns a pointer to
  523.  * "CD", which I use to create the "BCD" table.  The recursion is guaranteed
  524.  * to end if it ever gets to order -1, because the null table is
  525.  * guaranteed to have a for every symbol to the order 0 table.  This is
  526.  * the most complicated part of the modeling program, but it is
  527.  * necessary for performance reasons.
  528.  */
  529. CONTEXT *shift_to_next_context( CONTEXT *table, unsigned char c, int order)
  530. {
  531.     int i;
  532.     CONTEXT *new_lesser;
  533. /*
  534.  * First, try to find the new context by backing up to the lesser
  535.  * context and searching its link table.  If I find the link, we take
  536.  * a quick and easy exit, returning the link.  Note that their is a
  537.  * special Kludge for context order 0.  We know for a fact that
  538.  * the lesser context pointer at order 0 points to the null table,
  539.  * order -1, and we know that the -1 table only has a single link
  540.  * pointer, which points back to the order 0 table.
  541.  */
  542.     table = table->lesser_context;
  543.     if ( order == 0 )
  544.         return( table->links[ 0 ].next );
  545.     for ( i = 0 ; i <= table->max_index ; i++ )
  546.         if ( table->stats[ i ].symbol == c )
  547.             if ( table->links[ i ].next != NULL )
  548.                 return( table->links[ i ].next );
  549.             else
  550.                 break;
  551. /*
  552.  * If I get here, it means the new context did not exist.  I have to
  553.  * create the new context, add a link to it here, and add the backwards
  554.  * link to *his* previous context.  Creating the table and adding it to
  555.  * this table is pretty easy, but adding the back pointer isn't.  Since
  556.  * creating the new back pointer isn't easy, I duck my responsibility
  557.  * and recurse to myself in order to pick it up.
  558.  */
  559.     new_lesser = shift_to_next_context( table, c, order-1 );
  560. /*
  561.  * Now that I have the back pointer for this table, I can make a call
  562.  * to a utility to allocate the new table.
  563.  */
  564.     table = allocate_next_order_table( table, c, new_lesser );
  565.     return( table );
  566. }
  567.  
  568. /*
  569.  * Rescaling the table needs to be done for one of three reasons.
  570.  * First, if the maximum count for the table has exceeded 16383, it
  571.  * means that arithmetic coding using 16 and 32 bit registers might
  572.  * no longer work.  Secondly, if an individual symbol count has
  573.  * reached 255, it will no longer fit in a byte.  Third, if the
  574.  * current model isn't compressing well, the compressor program may
  575.  * want to rescale all tables in order to give more weight to newer
  576.  * statistics.  All this routine does is divide each count by 2.
  577.  * If any counts drop to 0, the counters can be removed from the
  578.  * stats table, but only if this is a leaf context.  Otherwise, we
  579.  * might cut a link to a higher order table.
  580.  */
  581. void rescale_table( CONTEXT *table )
  582. {
  583.     int i;
  584.  
  585.     if ( table->max_index == -1 )
  586.         return;
  587.     for ( i = 0 ; i <= table->max_index ; i++ )
  588.         table->stats[ i ].counts /= 2;
  589.     if ( table->stats[ table->max_index ].counts == 0 &&
  590.          table->links == NULL )
  591.     {
  592.         while ( table->stats[ table->max_index ].counts == 0 &&
  593.                 table->max_index >= 0 )
  594.             table->max_index--;
  595.         if ( table->max_index == -1 )
  596.         {
  597.             handle_free( (char __handle *) table->stats );
  598.             table->stats = NULL;
  599.         }
  600.         else
  601.         {
  602.             table->stats = (STATS __handle *)
  603.                 handle_realloc( (char __handle *) table->stats,
  604.                                  sizeof( STATS ) * ( table->max_index + 1 ) );
  605.             if ( table->stats == NULL )
  606.                 error_exit( "Error #11: reallocating stats space!" );
  607.         }
  608.     }
  609. }
  610.  
  611. /*
  612.  * This routine has the job of creating a cumulative totals table for
  613.  * a given context.  The cumulative low and high for symbol c are going to
  614.  * be stored in totals[c+2] and totals[c+1].  Locations 0 and 1 are
  615.  * reserved for the special ESCAPE symbol.  The ESCAPE symbol
  616.  * count is calculated dynamically, and changes based on what the
  617.  * current context looks like.  Note also that this routine ignores
  618.  * any counts for symbols that have already showed up in the scoreboard,
  619.  * and it adds all new symbols found here to the scoreboard.  This
  620.  * allows us to exclude counts of symbols that have already appeared in
  621.  * higher order contexts, improving compression quite a bit.
  622.  */
  623. void totalize_table( CONTEXT *table )
  624. {
  625.     int i;
  626.     unsigned char max;
  627.  
  628.     for ( ; ; )
  629.     {
  630.         max = 0;
  631.         i = table->max_index + 2;
  632.         totals[ i ] = 0;
  633.         for ( ; i > 1 ; i-- )
  634.         {
  635.             totals[ i-1 ] = totals[ i ];
  636.             if ( table->stats[ i-2 ].counts )
  637.                 if ( ( current_order == -2 ) ||
  638.                      scoreboard[ table->stats[ i-2 ].symbol ] == 0 )
  639.                      totals[ i-1 ] += table->stats[ i-2 ].counts;
  640.             if ( table->stats[ i-2 ].counts > max )
  641.                 max = table->stats[ i-2 ].counts;
  642.         }
  643. /*
  644.  * Here is where the escape calculation needs to take place.
  645.  */
  646.         if ( max == 0 )
  647.             totals[ 0 ] = 1;
  648.         else
  649.         {
  650.             totals[ 0 ] = (short int) ( 256 - table->max_index );
  651.             totals[ 0 ] *= table->max_index;
  652.             totals[ 0 ] /= 256;
  653.             totals[ 0 ] /= max;
  654.             totals[ 0 ]++;
  655.             totals[ 0 ] += totals[ 1 ];
  656.         }
  657.         if ( totals[ 0 ] < MAXIMUM_SCALE )
  658.             break;
  659.         rescale_table( table );
  660.     }
  661.     for ( i = 0 ; i < table->max_index ; i++ )
  662.     if (table->stats[i].counts != 0)
  663.             scoreboard[ table->stats[ i ].symbol ] = 1;
  664. }
  665.  
  666. /*
  667.  * This routine is called when the entire model is to be flushed.
  668.  * This is done in an attempt to improve the compression ratio by
  669.  * giving greater weight to upcoming statistics.  This routine
  670.  * starts at the given table, and recursively calls itself to
  671.  * rescale every table in its list of links.  The table itself
  672.  * is then rescaled.
  673.  */
  674. void recursive_flush( CONTEXT *table )
  675. {
  676.     int i;
  677.  
  678.     if ( table->links != NULL )
  679.         for ( i = 0 ; i <= table->max_index ; i++ )
  680.             if ( table->links[ i ].next != NULL )
  681.                 recursive_flush( table->links[ i ].next );
  682.     rescale_table( table );
  683. }
  684.  
  685. /*
  686.  * This routine is called to flush the whole table, which it does
  687.  * by calling the recursive flush routine starting at the order 0
  688.  * table.
  689.  */
  690. void flush_model()
  691. {
  692.     recursive_flush( contexts[ 0 ] );
  693. }
  694.  
  695. void error_exit( char *message)
  696. {
  697.     putc( '\n', stdout );
  698.     puts( message );
  699.     exit( -1 );
  700. }
  701.  
  702.  
  703.